﻿// Copyright (c) 2025 liucl
// Inject is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

#include "log_sink.hpp"

#include <WinSock2.h>
#include <ws2tcpip.h>

#include <string>

class udp_client {
  static constexpr int TX_BUFFER_SIZE = 1024 * 10;
  SOCKET socket_ = INVALID_SOCKET;
  sockaddr_in addr_ = {};

  static void init_winsock_() {
    WSADATA wsaData;
    auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rv != 0) {
    }
  }

  void cleanup_() {
    if (socket_ != INVALID_SOCKET) {
      ::closesocket(socket_);
    }
    socket_ = INVALID_SOCKET;
    ::WSACleanup();
  }

public:
  udp_client(const std::string &host, uint16_t port) {
    init_winsock_();

    addr_.sin_family = PF_INET;
    addr_.sin_port = htons(port);
    addr_.sin_addr.s_addr = INADDR_ANY;
    if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) {
      int last_error = ::WSAGetLastError();
      ::WSACleanup();
    }

    socket_ = ::socket(PF_INET, SOCK_DGRAM, 0);
    if (socket_ == INVALID_SOCKET) {
      int last_error = ::WSAGetLastError();
      ::WSACleanup();
    }

    int option_value = TX_BUFFER_SIZE;
    if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
                     reinterpret_cast<const char *>(&option_value),
                     sizeof(option_value)) < 0) {
      int last_error = ::WSAGetLastError();
      cleanup_();
    }
  }

  ~udp_client() { cleanup_(); }

  SOCKET fd() const { return socket_; }

  void send(const char *data, size_t n_bytes) {
    socklen_t tolen = sizeof(struct sockaddr);
    if (::sendto(socket_, data, static_cast<int>(n_bytes), 0,
                 (struct sockaddr *)&addr_, tolen) == -1) {
    }
  }
};

bool LogUDPSink::send_package(const char *data, size_t length) {
  static udp_client client("127.0.0.1", 8888);
  client.send(data, length);
  return true;
}
